package com.base;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Service
public abstract class BaseService<T> {

    protected abstract BaseMapper<T> getMapper();

    public int insert(T entity) {
        return getMapper().insert(entity);
    }

    public <R> int insert(R source, Class<T> target) {
        T entity = copy(source, target);
        return getMapper().insert(entity);
    }

    public int deleteById(Serializable id) {
        return getMapper().deleteById(id);
    }

    public int delete(Wrapper<T> queryWrapper) {
        return getMapper().delete(queryWrapper);
    }

    public int delete(T entity) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        queryWrapper.setEntity(entity);
        return getMapper().delete(queryWrapper);
    }

    public int deleteBatchIds(Collection ids) {
        return getMapper().deleteBatchIds(ids);
    }

    public int updateById(T entity) {
        return getMapper().updateById(entity);
    }

    public <R>int updateById(R source, Class<T> target) {
        T entity = copy(source, target);
        return getMapper().updateById(entity);
    }

    public int update(T entity, Wrapper<T> updateWrapper) {
        return getMapper().update(entity, updateWrapper);
    }

    public T selectById(Serializable id) {
        return getMapper().selectById(id);
    }

    public <R> R selectById(Serializable id, Class<R> target) {
        T source = getMapper().selectById(id);
        return copy(source, target);
    }

    public List<T> selectBatchIds(Collection ids) {
        return getMapper().selectBatchIds(ids);
    }

    public T selectOne(Wrapper<T> queryWrapper) {
        return getMapper().selectOne(queryWrapper);
    }

    public T selectOne(T entity) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        queryWrapper.setEntity(entity);
        return getMapper().selectOne(queryWrapper);
    }

    public <R> T selectOne(R source, Class<T> target) {
        T copy = copy(source, target);
        return selectOne(copy);
    }

    public <R,V> V selectOne(R source, Class<T> target1, Class<V> target2) {
        T entity = copy(source, target1);
        T t1 = selectOne(entity);
        return copy(t1, target2);
    }

    public Integer selectCount(Wrapper<T> queryWrapper) {
        return getMapper().selectCount(queryWrapper);
    }

    public Integer selectCount(T entity) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        queryWrapper.setEntity(entity);
        return getMapper().selectCount(queryWrapper);
    }

    public List<T> selectList(Wrapper<T> queryWrapper) {
        return getMapper().selectList(queryWrapper);
    }

    public <R> List<R> selectList(Wrapper<T> queryWrapper, Class<R> target) {
        List<T> tList = getMapper().selectList(queryWrapper);
        return copy(tList, target);
    }

    public List<T> selectList(T entity) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        queryWrapper.setEntity(entity);
        return getMapper().selectList(queryWrapper);
    }

    public <R> List<R> selectList(T entity, Class<R> target) {
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        queryWrapper.setEntity(entity);
        List<T> tList = getMapper().selectList(queryWrapper);
        return copy(tList, target);
    }

    public <R> List<T> queryList(R source, Class<T> target) {
        T copy = copy(source, target);
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        queryWrapper.setEntity(copy);
        return getMapper().selectList(queryWrapper);
    }

    public <R,V> List<V> queryList(R source, Class<T> target1, Class<V> target2) {
        T copy = copy(source, target1);
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        queryWrapper.setEntity(copy);
        List<T> tList = getMapper().selectList(queryWrapper);
        return copy(tList, target2);
    }

    public IPage<T> selectPage(IPage<T> page) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        return getMapper().selectPage(page, queryWrapper);
    }

    public IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper) {
        return getMapper().selectPage(page, queryWrapper);
    }

    public <R> IPage<R> selectPage(IPage<T> page, Class<R> classType) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        IPage<T> iPage = getMapper().selectPage(page, queryWrapper);
        return copy(iPage, classType);
    }

    public <R> IPage<R> selectPage(IPage<T> page, Wrapper<T> queryWrapper, Class<R> classType) {
        IPage<T> iPage = getMapper().selectPage(page, queryWrapper);
        return copy(iPage, classType);
}


    private <K,V> V copy(K source, V target){
        BeanUtils.copyProperties(source, target);
        return target;
    }

    private <K,V> V copy(K source, Class<V> classType){
        V target = null;
        try {
            target = classType.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        BeanUtils.copyProperties(source, target);
        return target;
    }

    private <K,V> List<V> copy(List<K> sourceList, Class<V> clazz){
        List<V> vList = new ArrayList<>();
        for (K source : sourceList) {
            V target = copy(source, clazz);
            vList.add(target);
        }
        return vList;
    }

    private <V> IPage copy(IPage page, Class<V> clazz){
        List<V> vList = new ArrayList<>();
        for (Object source : page.getRecords()) {
            vList.add(copy(source, clazz));
        }
        page.setRecords(vList);
        return page;
    }

}
